﻿/*  
	------------------------------------------------------------------------
	 NQ Software Development Kit Component
	
	 Homepage: http://www.awzhome.de/
	------------------------------------------------------------------------
	
	This Source Code Form is subject to the terms of the Mozilla Public
	License, v. 2.0. If a copy of the MPL was not distributed with this
	file, You can obtain one at http://mozilla.org/MPL/2.0/.
   
	The Original Code is code of NQ Software Development Kit Component.

	The Initial Developer of the Original Code is Andreas Weizel.
	Portions created by the Initial Developer are
	Copyright (C) 2012 Andreas Weizel. All Rights Reserved.
	
	Contributor(s): (none)
	
	------------------------------------------------------------------------
*/

using System;
using System.Collections.Generic;
using System.Text;
using AWZhome.NQ.Core;
using AWZhome.NQ.Core.Fluent;
using AWZhome.NQ.CommonServices;
using System.Windows.Controls;
using AWZhome.NQsdk.Visual;
using System.Windows.Data;
using AWZhome.NQsdk.Helpers;
using System.Windows;
using System.IO;
using System.Reflection;
using System.Windows.Input;
using Microsoft.Win32;
using System.Linq;
using AWZhome.NQ.Core.Serialization;
using NQCSServices = AWZhome.NQ.CommonServices.Services;
using NQsdkServices = AWZhome.NQsdk.Services;

namespace AWZhome.NQsdk.Services
{
	[NQExportedService]
	[NQServiceAttachment(CommonAttachLists.PreferenceUI_PrefViews)]
	public class SystemBrowserViewService : ViewServiceBase, NQsdkServices.ISystemBrowserViewService
	{
		private string _displayName;
		private SystemBrowserView _systemBrowserView;
		private ListBox _componentList;
		private ListBox _attachListList;
		private ListBox _interfaceList;

		private INQResourceGUIManager _servRes;
		private IBarManager _servBar;

		public SystemBrowserViewService(ISession sessionService)
			: base(sessionService)
		{
		}

		protected override bool CheckSessionType(ISession session)
		{
			return true;
		}

		public override string DisplayName
		{
			get
			{
				return _displayName;
			}
		}

		public override bool IsChanged
		{
			get
			{
				return false;
			}
		}

		public override bool CanBeClosed
		{
			get
			{
				return true;
			}
		}

		public override bool IsLoggable
		{
			get
			{
				return false;
			}
		}

		public override bool IsDocument
		{
			get
			{
				return true;
			}
		}

		public override object DisplayedObject
		{
			get
			{
				return _systemBrowserView;
			}
		}

		public override System.Windows.Media.ImageSource Icon
		{
			get
			{
				return null;
			}
		}

		public override ViewDisplayMode DockingType
		{
			get
			{
				return ViewDisplayMode.InClientArea | ViewDisplayMode.Floating;
			}
		}

		public override string ToolTip
		{
			get
			{
				return _displayName;
			}
		}

		public override void Initialize(string context)
		{
			base.Initialize(context);

			// Get resource service
			_servRes = ServiceCore
				.Get<NQCSServices.IResourceGUIService>()
				.To;
			_displayName = _servRes.GetResString("NQsdk", "SystemBrowserView.DisplayName");

			// Create visual view control and its BarService
			_systemBrowserView = new SystemBrowserView();
			_systemBrowserView.ServiceTreeView.SelectedItemChanged += ServiceTreeView_SelectedItemChanged;
			_servBar = _systemBrowserView.NQsdkSystemBrowserBar.BarService;
			_servBar.ItemClicked += new EventHandler<BarItemClickedEventArgs>(_servBar_ItemClicked);
			_servBar.DockBottom = false;
			_servBar.DockTop = true;
			_servBar.DockLeft = false;
			_servBar.DockRight = false;
			Stream xmlstream = Assembly.GetExecutingAssembly().GetManifestResourceStream("AWZhome.NQsdk.menudef.SDKBrowserMenu.xml");
			_servBar.CreateItemsFromXml(xmlstream);
			xmlstream.Close();
			_servBar.LoadBarSettings();

			// Set the data bindings
			_systemBrowserView.DataContext = this;
			((CollectionViewSource) _systemBrowserView.FindResource("ComponentSortedDataSource")).Source = this.GetComponentEntries();
			((CollectionViewSource) _systemBrowserView.FindResource("AttachListSortedDataSource")).Source = this.GetAttachListEntries();
			((CollectionViewSource) _systemBrowserView.FindResource("InterfaceSortedDataSource")).Source = this.GetInterfaceEntries();

			// Set ListViews
			_componentList = (ListBox) _systemBrowserView.NQsdkSystemBrowserBar.Children[0];
			_componentList.SelectionChanged += ComponentList_SelectionChanged;
			_componentList.MouseRightButtonUp += ComponentList_MouseRightButtonUp;

			_attachListList = (ListBox) _systemBrowserView.NQsdkSystemBrowserBar.Children[1];
			_attachListList.SelectionChanged += AttachListList_SelectionChanged;
			_attachListList.Visibility = Visibility.Hidden;

			_interfaceList = (ListBox) _systemBrowserView.NQsdkSystemBrowserBar.Children[2];
			_interfaceList.SelectionChanged += InterfaceList_SelectionChanged;
			_interfaceList.Visibility = Visibility.Hidden;

			// Always activate the toolbar (settings should take no effect)
			_servBar.GetBand("SDKBrowserToolbar").BandVisible = true;

			// Preselect first item
			_servBar.GetItem("SDKBrowserToolbar.ByComponent").ItemChecked = true;
			this._servBar_ItemClicked(this, new BarItemClickedEventArgs(_servBar.GetItem("SDKBrowserToolbar.ByComponent")));
		}

		public override void LoadContents()
		{
			base.LoadContents();

			// Read settings
			IPersistManager servPersist = ServiceCore
				.Get<NQCSServices.IPersistService>()
				.To;
			ConfigData splitter1Pos = servPersist.GetSetting("NQsdk", "sysBrowserSplitter1Pos", true);
			ConfigData splitter2Pos = servPersist.GetSetting("NQsdk", "sysBrowserSplitter2Pos", true);

			if (splitter1Pos != null)
			{
				_systemBrowserView.ListGrid.ColumnDefinitions[0].Width =
					(GridLength) (new GridLengthConverter()).ConvertFromString(splitter1Pos.AsString());
			}
			if (splitter2Pos != null)
			{
				_systemBrowserView.InnerListGrid.RowDefinitions[0].Height =
					(GridLength) (new GridLengthConverter()).ConvertFromString(splitter2Pos.AsString());
			}
		}

		public override void SaveContents(ViewSaveReason saveReason)
		{
			base.SaveContents(saveReason);

			// Save the settings
			IPersistManager servPersist = ServiceCore
				.Get<NQCSServices.IPersistService>()
				.To;
			servPersist.SetSetting("NQsdk", "sysBrowserSplitter1Pos",
				new ConfigData().FromString((new GridLengthConverter()).ConvertToString(_systemBrowserView.ListGrid.ColumnDefinitions[0].Width).Replace("*", "")), true);
			servPersist.SetSetting("NQsdk", "sysBrowserSplitter2Pos",
				new ConfigData().FromString((new GridLengthConverter()).ConvertToString(_systemBrowserView.InnerListGrid.RowDefinitions[0].Height).Replace("*", "")), true);

			//_servBar.SaveBarSettings();
		}

		#region Private methods

		private void _servBar_ItemClicked(object sender, BarItemClickedEventArgs e)
		{
			switch (e.Item.ItemKey)
			{
				case "SDKBrowserToolbar.ByComponent":
					// Show component list
					_componentList.Visibility = Visibility.Visible;
					_attachListList.Visibility = Visibility.Hidden;
					_interfaceList.Visibility = Visibility.Hidden;

					// Preselect first item
					if (_componentList.Items.Count > 0)
					{
						_componentList.SelectedItem = null;
						_componentList.SelectedIndex = 0;
					}

					break;

				case "SDKBrowserToolbar.ByAttachList":
					// Show "AttachList list"
					_componentList.Visibility = Visibility.Hidden;
					_attachListList.Visibility = Visibility.Visible;
					_interfaceList.Visibility = Visibility.Hidden;

					// Preselect first item
					if (_attachListList.Items.Count > 0)
					{
						_attachListList.SelectedItem = null;
						_attachListList.SelectedIndex = 0;
					}

					break;

				case "SDKBrowserToolbar.ByInterface":
					// Show interface list
					_componentList.Visibility = Visibility.Hidden;
					_attachListList.Visibility = Visibility.Hidden;
					_interfaceList.Visibility = Visibility.Visible;

					// Preselect first item
					if (_interfaceList.Items.Count > 0)
					{
						_interfaceList.SelectedItem = null;
						_interfaceList.SelectedIndex = 0;
					}

					break;

				case "SDKMenuBrowserCtx.Component.ExportDefinition":
					ComponentEntry compEntry = _componentList.SelectedItem as ComponentEntry;
					if (compEntry != null)
					{
						this.ExportComponentXMLDefinition(compEntry);
					}
					break;

				default:
					break;
			}
		}

		private void ComponentList_MouseRightButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
		{
			ComponentEntry compEntry = _componentList.SelectedItem as ComponentEntry;
			if (compEntry != null)
			{
				// Show context menu
				IBarBand browserCtxMenu = _servBar.GetBand("SDKMenuBrowserCtx.Component");
				Point mousePos = Mouse.GetPosition(_componentList);
				mousePos = _componentList.PointToScreen(mousePos);
				browserCtxMenu.ShowAsContextMenu((int) mousePos.X, (int) mousePos.Y);
			}
		}

		private void ComponentList_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			ComponentEntry compEntry = _componentList.SelectedItem as ComponentEntry;
			if (compEntry != null)
			{
				if (compEntry.IsRegularComponent)
				{
					((CollectionViewSource) _systemBrowserView.FindResource("ServiceSortedDataSource")).Source =
						this.GetServiceEntries(s => ((compEntry.Name == null) || (compEntry.Name == s.ServiceInfo.ParentComponent)));
				}
				else
				{
					((CollectionViewSource) _systemBrowserView.FindResource("ServiceSortedDataSource")).Source = this.GetServiceEntries(null);
				}
			}
		}

		private void AttachListList_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			string attachListEntry = _attachListList.SelectedItem as string;
			if (attachListEntry != null)
			{
				((CollectionViewSource) _systemBrowserView.FindResource("ServiceSortedDataSource")).Source =
					this.GetServiceEntries(
						s => ((s.ServiceInfo.AttachedTo != null) && (s.ServiceInfo.AttachedTo.Contains<string>(attachListEntry)))
					);
			}
		}

		private void InterfaceList_SelectionChanged(object sender, SelectionChangedEventArgs e)
		{
			Type interfaceEntry = _interfaceList.SelectedItem as Type;
			if (interfaceEntry != null)
			{
				((CollectionViewSource) _systemBrowserView.FindResource("ServiceSortedDataSource")).Source =
					this.GetServiceEntries(
						s => ((s.ServiceInfo.InterfaceTypes != null) && (s.ServiceInfo.InterfaceTypes.Contains<Type>(interfaceEntry)))
					);
			}
		}

		private void ServiceTreeView_SelectedItemChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<object> e)
		{
			ServiceEntry serviceEntry = _systemBrowserView.ServiceTreeView.SelectedItem as ServiceEntry;

			// Bind the ServiceEntry to the displaying control
			_systemBrowserView.ComponentServiceInfo.ServiceEntry = serviceEntry;

			// Bind the ComponentEntry representing the component of the selected service
			try
			{
				List<ComponentEntry> componentEntries =
					((CollectionViewSource) _systemBrowserView.FindResource("ComponentSortedDataSource")).Source as List<ComponentEntry>;
				ComponentEntry foundEntry = componentEntries.Find(ce => ce.Name == serviceEntry.ServiceInfo.ParentComponent);
				_systemBrowserView.ComponentServiceInfo.ComponentEntry = foundEntry;
			}
			catch (Exception)
			{
				_systemBrowserView.ComponentServiceInfo.ComponentEntry = null;
			}
		}

		private void ExportComponentXMLDefinition(ComponentEntry componentEntry)
		{
			if (componentEntry.IsRegularComponent)
			{
				// Export a single component
				SaveFileDialog saveFileDialog = new SaveFileDialog();
				saveFileDialog.Filter = _servRes.GetResString("NQsdk", "ServiceBrowserView.FileFilterXMLDef") + "|*.xml|"
					+ _servRes.GetResString("NQCS", "FileFilter.AllFiles") + "|*.*";
				saveFileDialog.FileName = componentEntry.Name + ".xml";
				saveFileDialog.AddExtension = true;
				if (saveFileDialog.ShowDialog().Value)
				{
					// Collect and serialize service information
					NQComponentInfoSerializer serializer = new NQComponentInfoSerializer(Encoding.UTF8);
					using (FileStream stream = new FileStream(saveFileDialog.FileName, FileMode.Create))
					{
						INQComponentInfo compInfo = componentEntry.ComponentInfo;
						Type[] servInterfaces = NQServiceManager.Instance.GetServiceList();
						INQServiceInfo[] servInfos = new INQServiceInfo[servInterfaces.Length];
						for (int i = 0; i < servInterfaces.Length; i++)
						{
							servInfos[i] = NQServiceManager.Instance.GetServiceInfo(servInterfaces[i]);
						}
						serializer.WriteComponentInfo(stream, compInfo, servInfos);

						stream.Flush();
						stream.Close();
					}
				}
			}
			else
			{
				// Export all components
				System.Windows.Forms.FolderBrowserDialog folderBrowser = new System.Windows.Forms.FolderBrowserDialog();
				folderBrowser.Description = _servRes.GetResString("NQsdk", "ServiceBrowserView.DirSelectDescXMLDef");
				if (folderBrowser.ShowDialog() == System.Windows.Forms.DialogResult.OK)
				{
					// Export all components
					try
					{
						NQComponentInfoSerializer serializer = new NQComponentInfoSerializer(Encoding.UTF8);
						foreach (var comp in NQServiceManager.Instance.GetComponentList())
						{
							INQComponentInfo compInfo = NQServiceManager.Instance.GetComponentInfo(comp);
							if (compInfo != null)
							{
								using (FileStream stream = new FileStream(Path.Combine(folderBrowser.SelectedPath, compInfo.Name + ".xml"), FileMode.Create))
								{
									Type[] servInterfaces = NQServiceManager.Instance.GetServiceList();
									INQServiceInfo[] servInfos = new INQServiceInfo[servInterfaces.Length];
									for (int i = 0; i < servInterfaces.Length; i++)
									{
										servInfos[i] = NQServiceManager.Instance.GetServiceInfo(servInterfaces[i]);
									}
									serializer.WriteComponentInfo(stream, compInfo, servInfos);

									stream.Flush();
									stream.Close();
								}
							}
						}
					}
					catch (Exception ex)
					{
						ServiceCore.Log.From(this).OnException(ex).Error("ExportComponentXMLDefinition");
					}
				}
			}
		}

		private List<ComponentEntry> GetComponentEntries()
		{
			List<ComponentEntry> entries = new List<ComponentEntry>();

			// Create a list of all displayed component objects
			foreach (string compName in NQServiceManager.Instance.GetComponentList())
			{
				ComponentEntry compEntry = new ComponentEntry();
				compEntry.ComponentInfo = NQServiceManager.Instance.GetComponentInfo(compName);
				compEntry.Name = compEntry.ComponentInfo.Name;
				compEntry.IsRegularComponent = true;
				entries.Add(compEntry);
			}

			// Now create the "(all)" element
			INQResourceGUIManager servRes = ServiceCore
				.Get<NQCSServices.IResourceGUIService>()
				.To;
			ComponentEntry allEntry = new ComponentEntry();
			allEntry.IsRegularComponent = false;
			allEntry.Name = servRes.GetResString("NQsdk", "ServiceBrowserView.ListAll");
			entries.Add(allEntry);

			return entries;
		}

		private List<string> GetAttachListEntries()
		{
			return new List<string>(NQServiceManager.Instance.GetAllAttachLists());
		}

		private List<Type> GetInterfaceEntries()
		{
			// Iterate through all services and collect their interfaces
			HashSet<Type> interfaceList = new HashSet<Type>();
			foreach (Type serviceInterface in ServiceCore.AllServices)
			{
				INQServiceInfo servInfo = ServiceCore.ServiceMetaInfo(serviceInterface);
				if (servInfo.InterfaceTypes != null)
				{
					foreach (Type interfaceImplementation in servInfo.InterfaceTypes)
					{
						if (!interfaceList.Contains(interfaceImplementation))
						{
							interfaceList.Add(interfaceImplementation);
						}
					}
				}
			}

			return interfaceList.ToList<Type>();
		}

		private List<ServiceEntry> GetServiceEntries(Func<ServiceEntry, bool> condition)
		{
			Dictionary<string, ServiceEntry> entries = new Dictionary<string, ServiceEntry>();

			// Create a list of all displayed service object
			foreach (Type serviceInterface in ServiceCore.AllServices)
			{
				ServiceEntry entry = new ServiceEntry();
				entry.ServiceInfo = ServiceCore.ServiceMetaInfo(serviceInterface);
				entry.IsSingleInstance = entry.ServiceInfo.SingleInstance;
				entries.Add(entry.ServiceInfo.ServiceInterface.FullName, entry);
			}

			// Now create sub-entries for substituted services
			foreach (ServiceEntry entry in entries.Values)
			{
				if (entry.ServiceInfo.Substitutes != null)
				{
					foreach (Type substServInterface in entry.ServiceInfo.Substitutes)
					{
						entries[substServInterface.FullName].IsSubstituted = true;
						entries[substServInterface.FullName].SubEntries.Add(entry);
					}
				}
			}

			if (condition != null)
			{
				return new List<ServiceEntry>(entries.Values.Where<ServiceEntry>(condition));
			}
			else
			{
				return new List<ServiceEntry>(entries.Values);
			}
		}

		#endregion
	}
}
